/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#pragma once

#include <OmenEngine>
#include <OmenEventHandler.h>

#include "IOmenCamera.h"
#include "OmenCollisionEvent.h"
#include "OmenMath.h"

#include <functional>

namespace Omen
{
    class IPhysicalObject
    {
    ///
    /// Definitions of default camera parameters
    ///
    #define ORIGO  Omen::Vector3d(0.0,0.0,0.0)
    #define X_AXIS Omen::Vector3d(1.0,0.0,0.0)
    #define Y_AXIS Omen::Vector3d(0.0,1.0,0.0)
    #define Z_AXIS Omen::Vector3d(0.0,0.0,1.0)

    public:

    public:
        virtual ~IPhysicalObject();

        ///
        /// Camera position and 
        ///
        virtual Omen::Vector3d    position() const;                     /// <summary> Returns the position vector in world coordinates</summary>
        virtual void  setPosition(const Omen::Vector3d& position);      /// <summary> Set the camera position in global coordinates

        ///
        /// Set position and look at direction with setLookAT
        ///
        virtual void  setLookAt(const Omen::Vector3d& target);          /// <summary> Set the camera target coordinate, where the camera is looking at</summary>
        
        ///
        /// Orthonormal direction base vectors
        ///
        virtual Omen::Vector3d    right() const;                        /// <summary> Returns the normalized direction vector pointing up </summary>
        virtual Omen::Vector3d    up() const;                           /// <summary> Returns the normalized direction vector pointing up </summary>
        virtual Omen::Vector3d    forward() const;                      /// <summary> Returns the normalized direction vector pointing forward</summary>

        virtual void  setRight(const Omen::Vector3d& up) ;              /// <summary> Set the camera right-direction</summary>
        virtual void  setUp(const Omen::Vector3d& up);                  /// <summary> Set the camera up-direction</summary>
        virtual void  setForward(const Omen::Vector3d& up) ;            /// <summary> Set the camera forward-direction</summary>

        ///
        /// Roatation angles
        ///
        virtual Omen::Float pitch() const;                              /// <summary> The angle in degrees around the x-axis, turning from from down-to-up e.g. clock-wise</summary>
        virtual Omen::Float yaw() const;                                /// <summary> The angle in degres around the y-axis, turning from right-to-left e.g. clock-wise</summary>
        virtual Omen::Float roll() const;                               /// <summary> The angle in degres around the z-axis, turning clock-wise</summary>

        virtual void setPitch( Omen::Float pitch);                      /// <summary> The angle in degrees around the x-axis, turning from from down-to-up e.g. clock-wise</summary>
        virtual void setYaw( Omen::Float yaw);                          /// <summary> The angle in degres around the y-axis, turning from right-to-left e.g. clock-wise</summary>
        virtual void setRoll(Omen::Float roll);                         /// <summary> The angle in degres around the z-axis, turning clock-wise</summary>

        ///
        /// Velocity and acceleration
        ///
        virtual Omen::Vector3d velocity() const;                        /// <summary> Returns the velocity of the camera </summary>
        virtual Omen::Vector3d maxVelocity() const;                     /// <summary> Returns the maximum camera velocity </summary>
        virtual Omen::Vector3d acceleration() const;                    /// <summary> Returns the acceleration of the camera</summary>

        virtual void setVelocity( const Omen::Vector3d& velocity );      /// <summary> Set's the current camera velocity </summary>
        virtual void setMaxVelocity( const Omen::Vector3d& velocity );  /// <summary> Set's the velocity of the camera</summary>
        virtual void setAcceleration( const Omen::Vector3d& acceleration ); /// <summary> Set's the acceleration of the camera</summary>

        ///
        /// Camera rotation speed
        ///
        virtual Omen::Float rotationSpeed() const;                      /// <summary> Returns the rotation speed of the camera </summary>
        virtual void setRotationSpeed( Omen::Float speed );             /// <summary> Sets the rotation speed of the camera </summary>

        /// Collision response handler
        void OnCollisionEvent( const Omen::CollisionEvent* event );

    protected:        
        IPhysicalObject();

        void updateVelocity( const Omen::Vector3d& direction, Omen::Float elapsedTime);
        void move(Omen::Float dx, Omen::Float dy, Omen::Float dz);

    private:
        Omen::Float     m_mass;                 // Mass of object in kilo-grams (kg)
        Omen::Float     m_density;              // Density of the object material, kilograms per cubic meter (kg/m^3)
        Omen::Sphere    m_boundingSphere;       // Bounding Sphere of the object
        Omen::AABB      m_boundingBox;          // Axis Aligned Bounding Box(AABB) of the object

        Omen::Matrix4x4 m_transformation;       // Transformation matrix consisting of right,up and forward vectors

        // Functions for getting data from Omen::IObject
        std::function< Omen::Float(void) >  getMass;
        std::function< Omen::Float(void) >  getDensity;
        std::function< Omen::AABB(void) >   getBoundingBox;
        std::function< Omen::Sphere(void) > getBoundingSphere;
        
        std::function< Omen::Vector3d(void) > getVelocity;
        std::function< void( Omen::Matrix4x4& ) > getTransformation;

        std::shared_ptr<Omen::IMesh>    m_pMesh; // This is for triangle collision tests

        Vector3d        m_position;             // The position of the camera
        Omen::Float     m_rotationSpeed;        // The rotation speed of the camera
        
        Vector3d        m_forward;
        Vector3d        m_right;
        Vector3d        m_up;
        
        Vector3d        m_velocity;             // Velocity vector (vx,vy,vz)
        Vector3d        m_angularVelocity;      // Angulary velocity (vYaw,vPitch,vRoll)
        Vector3d        m_maxVelocity;          // Velocity vector (vx,vy,vz)
        Vector3d        m_acceleration;         // Acceleration vector (ax,ay,az)
        Vector3d        m_torque;               // Torque vector (vx,vy,vz)

        Omen::Float     m_yaw, m_pitch, m_roll;
        Omen::Float     m_scaleX, m_scaleY, m_scaleZ;
    };
}